# Form Rows

## Examples


### Basic

```typescript
import React, { Component } from 'react';

import FormRows, {
    FormRowsRequestMoveHandler,
    RowRequestRemoveHandler,
} from '@splunk/react-ui/FormRows';
import Text from '@splunk/react-ui/Text';
import { createDOMID } from '@splunk/ui-utils/id';


class Basic extends Component<object, { items: React.ReactElement[] }> {
    constructor(props: object) {
        super(props);

        const items = [
            <FormRows.Row index={0} key="0" onRequestRemove={this.handleRequestRemove}>
                <Text defaultValue="Just another" />
            </FormRows.Row>,
            <FormRows.Row index={1} key="1" onRequestRemove={this.handleRequestRemove}>
                <Text defaultValue="Row in the form" />
            </FormRows.Row>,
        ];
        this.state = {
            items,
        };
    }

    handleRequestAdd = () => {
        this.setState((state) => ({
            items: FormRows.addRow(
                <FormRows.Row
                    index={state.items.length}
                    key={createDOMID()}
                    onRequestRemove={this.handleRequestRemove}
                >
                    <Text />
                </FormRows.Row>,
                state.items
            ),
        }));
    };

    handleRequestMove: FormRowsRequestMoveHandler = ({ fromIndex, toIndex }) => {
        this.setState((state) => ({
            items: FormRows.moveRow(fromIndex, toIndex, state.items),
        }));
    };

    handleRequestRemove: RowRequestRemoveHandler = (e, { index }) => {
        this.setState((state) => ({
            items: FormRows.removeRow(index, state.items),
        }));
    };

    render() {
        return (
            <FormRows
                onRequestAdd={this.handleRequestAdd}
                onRequestMove={this.handleRequestMove}
                style={{ width: 300 }}
            >
                {this.state.items}
            </FormRows>
        );
    }
}

export default Basic;
```



### Custom Add Menu

The 'Add row' button can be replaced with a button, multiple buttons, or any other content you want to show below the Form Rows.

```typescript
import React, { Component } from 'react';

import FormRows, {
    FormRowsRequestMoveHandler,
    RowRequestRemoveHandler,
} from '@splunk/react-ui/FormRows';
import Number from '@splunk/react-ui/Number';
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
import Slider from '@splunk/react-ui/Slider';
import Text from '@splunk/react-ui/Text';
import { createDOMID } from '@splunk/ui-utils/id';


class Menu extends Component<object, { items: React.ReactElement[] }> {
    constructor(props: object) {
        super(props);

        this.state = {
            items: [],
        };
    }

    handleRequestAdd: SelectChangeHandler = (e, data) => {
        let element: React.ReactElement;
        const { value } = data;
        switch (value) {
            case '1':
                element = <Text />;
                break;
            case '2':
                element = <Slider defaultValue={3} />;
                break;
            case '3':
                element = <Number />;
                break;
            default:
                break;
        }
        this.setState((state) => ({
            items: FormRows.addRow(
                <FormRows.Row
                    index={state.items.length}
                    key={createDOMID()}
                    onRequestRemove={this.handleRequestRemove}
                >
                    {element}
                </FormRows.Row>,
                state.items
            ),
        }));
    };

    handleRequestMove: FormRowsRequestMoveHandler = ({ fromIndex, toIndex }) => {
        this.setState((state) => ({
            items: FormRows.moveRow(fromIndex, toIndex, state.items),
        }));
    };

    handleRequestRemove: RowRequestRemoveHandler = (e, { index }) => {
        this.setState((state) => ({
            items: FormRows.removeRow(index, state.items),
        }));
    };

    render() {
        const formMenu = (
            <Select
                appearance="default"
                onChange={this.handleRequestAdd}
                placeholder="Add"
                value={0}
            >
                <Select.Option label="Text" value="1" />
                <Select.Option label="Slider" value="2" />
                <Select.Option label="Number" value="3" />
            </Select>
        );

        return (
            <FormRows onRequestMove={this.handleRequestMove} menu={formMenu}>
                {this.state.items}
            </FormRows>
        );
    }
}

export default Menu;
```



### spanStyle

```typescript
import React, { Component } from 'react';

import FormRows, {
    FormRowsRequestMoveHandler,
    RowRequestRemoveHandler,
} from '@splunk/react-ui/FormRows';
import Text from '@splunk/react-ui/Text';
import { createDOMID } from '@splunk/ui-utils/id';

const spanStyle: React.CSSProperties = {
    alignSelf: 'center',
};

class Header extends Component<object, { items: React.ReactElement[] }> {
    constructor(props: object) {
        super(props);

        const items = [
            <FormRows.Row index={0} key="uniqueRowUno" onRequestRemove={this.handleRequestRemove}>
                <Text defaultValue="sourceip" />
                <span style={spanStyle}>=</span>
                <Text defaultValue="192.168.1.1" />
            </FormRows.Row>,
            <FormRows.Row index={1} key="uniqueRowDos" onRequestRemove={this.handleRequestRemove}>
                <Text defaultValue="uid" />
                <span style={spanStyle}>=</span>
                <Text defaultValue="johndoe" />
            </FormRows.Row>,
        ];
        this.state = {
            items,
        };
    }

    handleRequestAdd = () => {
        this.setState((state) => ({
            items: FormRows.addRow(
                <FormRows.Row
                    index={state.items.length}
                    key={createDOMID()}
                    onRequestRemove={this.handleRequestRemove}
                >
                    <Text describedBy="header-key" />
                    <span style={spanStyle}>=</span>
                    <Text describedBy="header-value" />
                </FormRows.Row>,
                state.items
            ),
        }));
    };

    handleRequestMove: FormRowsRequestMoveHandler = ({ fromIndex, toIndex }) => {
        this.setState((state) => ({
            items: FormRows.moveRow(fromIndex, toIndex, state.items),
        }));
    };

    handleRequestRemove: RowRequestRemoveHandler = (e, { index }) => {
        this.setState((state) => ({
            items: FormRows.removeRow(index, state.items),
        }));
    };

    render() {
        const header = (
            <div>
                <span
                    style={{
                        display: 'inline-block',
                        width: 172,
                    }}
                    id="header-key"
                >
                    Key
                </span>
                <span style={{ display: 'inline-block' }} id="header-value">
                    Value
                </span>
            </div>
        );
        return (
            <FormRows
                addLabel="Add input"
                header={header}
                onRequestAdd={this.handleRequestAdd}
                onRequestMove={this.handleRequestMove}
                style={{ width: 400 }}
            >
                {this.state.items}
            </FormRows>
        );
    }
}

export default Header;
```



### Reorder only

The add and delete functionality can be removed by not including the onRequestAdd handler on Form Rows and the onRequestRemove handler on Row. The functionality of reordering Rows will still remain intact. If users can add, they should be able to delete as well.

```typescript
import React, { Component } from 'react';

import FormRows, { FormRowsRequestMoveHandler } from '@splunk/react-ui/FormRows';
import Text from '@splunk/react-ui/Text';


class ReorderOnly extends Component<object, { items: React.ReactElement[] }> {
    constructor(props: object) {
        super(props);

        const items = [
            <FormRows.Row index={0} key="0">
                <Text inline defaultValue="You can move me" />
            </FormRows.Row>,
            <FormRows.Row index={1} key="1">
                <Text inline defaultValue="But you can't Add/Remove me" />
            </FormRows.Row>,
        ];
        this.state = {
            items,
        };
    }

    handleRequestMove: FormRowsRequestMoveHandler = ({ fromIndex, toIndex }) => {
        this.setState((state) => ({
            items: FormRows.moveRow(fromIndex, toIndex, state.items),
        }));
    };

    render() {
        return (
            <FormRows onRequestMove={this.handleRequestMove} style={{ width: 300 }}>
                {this.state.items}
            </FormRows>
        );
    }
}

export default ReorderOnly;
```




## API


### FormRows API

#### Props

| Name | Type | Required | Default | Description |
|------|------|------|------|------|
| addLabel | string | no | _('Add row') | Label on the Add row button. Ignored when menu prop is defined. |
| disabled | boolean | no |  | Disable the Add row button, the Remove button and the sort/drag action. |
| elementRef | React.Ref<HTMLDivElement> | no |  | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
| header | React.ReactNode | no |  | Header for the rows. |
| menu | React.ReactNode | no |  | Replaces Add row button with custom content or controls. |
| onRequestAdd | React.MouseEventHandler<HTMLButtonElement \| HTMLAnchorElement> | no |  | Callback when the Add row button is clicked. If `onRequestAdd` is defined, 'onRequestRemove' should be defined in `<FormRows.Row>`. Neither should be defined for a reorder-only variant of `<FormRows>`. |
| onRequestMove | FormRowsRequestMoveHandler | no |  | Callback when sort action completes. Omit this to make rows unsortable. |

#### Types

| Name | Type | Description |
|------|------|------|
| FormRowsRequestMoveHandler | (data: { fromIndex: number; toIndex: number }) => void |  |



### FormRows.Row API

#### Props

| Name | Type | Required | Default | Description |
|------|------|------|------|------|
| children | React.ReactNode | no |  |  |
| elementRef | React.Ref<HTMLDivElement> | no |  | A React ref which is set to the DOM element when the component mounts and null when it unmounts. |
| index | number | no |  | Index of the row. This is required if the rows are sortable. |
| onRequestRemove | RowRequestRemoveHandler | no |  | Callback when Remove button is clicked. |
| value | React.ReactNode | no |  | The contents of Row |

#### Types

| Name | Type | Description |
|------|------|------|
| RowRequestRemoveHandler | (     event: React.MouseEvent<HTMLButtonElement>,     data: { index: number } ) => void |  |





